package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;

/**
 * @author Y1n
 * @date 2021/11/19 11:58
 * @decs minicat的主类
 **/
public class Bootstrap {

    /*定义stock监听的端口  */
    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private Mapper mapper = new Mapper();

    /**
     * Minicat启动需要初始化的一些操作
     */
    public void start1() throws IOException {
        // 完成 minicat 1.0 功能 :
        // 浏览器请求 http://localhost:8080返回固定的字符串"hello minicat!"
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("minicat start on port => " + port);

        while (true) {
            System.out.println("进来了");
            Socket socket = serverSocket.accept();
            // 获取输出流
            OutputStream outputStream = socket.getOutputStream();
            String str = "hello minicat!";
            String responseText = HttpPortocolUtil.getHttpHeaderSuccess(str.length()) + str;

            outputStream.write(responseText.getBytes(StandardCharsets.UTF_8));

            socket.close();
        }

    }

    public void start2() throws IOException {
        // 完成 minicat 2.0 功能 :
        // 浏览器请求 http://localhost:8080/index.html 访问到对应的html页面 以及404页面
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("minicat start on port => " + port);

        while (true) {

            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            response.outputHtml(request.getUrl());

            socket.close();

        }

    }


    public void start3() throws Exception {
        // 完成 minicat 3.0 功能 :
        // 浏览器请求 http://localhost:8080/lagou 访问对应的servlet

        // 加载web.xml配置文件
        loadServlet();


        // 定义线程池
        //  int corePoolSize  基本大小,
        //  int maximumPoolSize 最大数量,
        //  long keepAliveTime 超过多久销毁,
        //  TimeUnit unit 上面参数的单位,
        //  BlockingQueue<Runnable> workQueue 请求的缓冲队列,
        //  ThreadFactory threadFactory 线程的工厂,
        //  RejectedExecutionHandler handler 线程池的拒绝策略  任务太多时按照什么策略拒绝
        int corePoolSize = 10 ;
        int maximumPoolSize = 50 ;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);

        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("minicat start on port => " + port);

        while (true) {
            Socket socket = serverSocket.accept();
            // 使用自定义的多线程
            RequestProcessor requestProcessor = new RequestProcessor(socket, servletMap);
            //requestProcessor.start();
            // 使用线程池
            executor.execute(requestProcessor);

        }

    }

    /**
     * @author Y1n
     * @date 2021/11/30 11:16
     * @description 去加载server.xml配置文件 获取当前项目的根路径
     * @param
     * @return
     */
    private void loadServerXml(){
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> service = rootElement.selectNodes("//Service");
            // <servlet>
            //        <servlet-name>lagou</servlet-name>
            //        <servlet-class>server.LagouServlet</servlet-class>
            //    </servlet>
            List<MapperHost> mapperHosts = new ArrayList<>();
            for (Element element : service) {
                // 记录host
                MapperHost mapperHost = new MapperHost();

                Element connectorElement = (Element) element.selectSingleNode("Connector");
                System.out.println(connectorElement);
                // 获取connect中的端口 8080
                String port = connectorElement.attributeValue("port");


                Element engineElement = (Element) element.selectSingleNode("Engine");
                Element hostElement =(Element) engineElement.selectSingleNode("Host");
                String localName = hostElement.attributeValue("name");

                // 设置 host
                mapperHost.setMapperHost(localName+":"+port);

                String appBase = hostElement.attributeValue("appBase");
                // 根据 appBase 找到对应的 wabapp下的项目遍历 获取其中web.xml的servlet
                File file = new File(appBase);
                System.out.println(file);
                // 获取文件下的不同的项目
                File[] files = file.listFiles();
                List<MapperContext> mapperContexts = new ArrayList<>();
                for (File f: files) {

                    // 获取ocntext 每个项目的 上下文
                    String context = f.getName();
                    // 记录 context
                    MapperContext mapperContext = new MapperContext();
                    //  将context set  也就是项目名 成
                    mapperContext.setMapperContext(context);

                    List<MapperWrapper> mapperWrappers = new ArrayList<>();
                    File[] listFiles = f.listFiles();
                    // 写死
                    File webFile = listFiles[1];
                    //webFile :  F:\webapps\demo1\web.xml
                    // 解析 web.xml 将
                    InputStream inputStream = new FileInputStream(webFile);
                    SAXReader saxReaderServlet = new SAXReader();
                    Document read = saxReaderServlet.read(inputStream);
                    Element rootXmlElement  = read.getRootElement();
                    // 找到多个 servlet 将他存到warp
                    List<Element> servletElements = (List<Element>) rootXmlElement.selectNodes("//servlet");
                    for (Element servletElement : servletElements) {
                        MapperWrapper mapperWrapper = new MapperWrapper();
                        // <servlet-name>lagou</servlet-name>
                        Element servletnameElement = (Element) servletElement.selectSingleNode("servlet-name");
                        String servletName = servletnameElement.getStringValue();
                        // <servlet-class>server.LagouServlet</servlet-class>
                        Element servletclassElement = (Element) servletElement.selectSingleNode("servlet-class");
                        String servletClass = servletclassElement.getStringValue();
                        // 根据servlet-name的值找到url-pattern
                        Element servletMapping = (Element) rootXmlElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                        // /lagou
                        String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                        // 将url 封装到warpper中
                        mapperWrapper.setUrl(urlPattern);
                        mapperWrapper.setServlet((HttpServlet)Class.forName(servletClass).newInstance());
                        mapperWrappers.add(mapperWrapper);
                    }
                    mapperContext.setMappedWrappers(mapperWrappers);
                    mapperContexts.add(mapperContext);
                }
                mapperHosts.add(mapperHost);
                mapperHost.setMapperContexts(mapperContexts);

            }
            mapper.setMapperHosts(mapperHosts);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public void start4() throws Exception {
        // 开发Minicat V4.0，在已有Minicat基础上进一步扩展，
        // 模拟出webapps部署效果 磁盘上放置一个webapps目录，webapps中可以有多个项目，
        // 例如demo1、demo2、demo3... 每个项目中含有servlet，
        // 可以根据请求url定位对应servlet进一步处理。

        // 加载server.xml 配置文件
        loadServerXml();

        // 加载web.xml配置文件
        //loadServlet();


        // 定义线程池
        //  int corePoolSize  基本大小,
        //  int maximumPoolSize 最大数量,
        //  long keepAliveTime 超过多久销毁,
        //  TimeUnit unit 上面参数的单位,
        //  BlockingQueue<Runnable> workQueue 请求的缓冲队列,
        //  ThreadFactory threadFactory 线程的工厂,
        //  RejectedExecutionHandler handler 线程池的拒绝策略  任务太多时按照什么策略拒绝
        int corePoolSize = 10 ;
        int maximumPoolSize = 50 ;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);

        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("minicat start on port => " + port);

        while (true) {
            Socket socket = serverSocket.accept();
            // 使用自定义的多线程
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            //requestProcessor.start();
            // 使用线程池
            executor.execute(requestProcessor);

        }

    }


    private Map<String, HttpServlet> servletMap = new HashMap<>();

    /**
     * @param
     * @return
     * @author Y1n
     * @date 2021/11/19 16:58
     * @description 加载解析web.xml 初始化
     */
    private void loadServlet() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> servlets = rootElement.selectNodes("//servlet");
            // <servlet>
            //        <servlet-name>lagou</servlet-name>
            //        <servlet-class>server.LagouServlet</servlet-class>
            //    </servlet>
            for (Element element : servlets) {
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                Element servletNameClass = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletNameClass.getStringValue();
                //  <servlet-mapping>
                //        <servlet-name>lagou</servlet-name>
                //        <servlet-class>/lagou</servlet-class>
                //    </servlet-mapping>
                // 根据servlet-name的值找到对应的mapping
                Element servletMappingElement = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // 根据servlet-name 找到 url-pattern
                Element servletMapping = (Element) servletMappingElement.selectSingleNode("url-pattern");
                String urlPattern = servletMapping.getStringValue();
                servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).getDeclaredConstructor().newInstance());

            }


        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param
     * @return
     * @author Y1n
     * @date 2021/11/19 11:59
     * @description minicat启动入库
     */
    public static void main(String[] args) {

        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动tomcat
            bootstrap.start4();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}
